//UNI 官方目前只提供了ble（低功耗）蓝牙设备的连接和通联接口 以下搜索设备连接设备与设备通联 都是指的ble蓝牙设备。经典蓝牙设备的通联可能需要去插件市场使用别人提供的原生安卓蓝牙插件，这里不进行补充

let BluetoothDeviceFoundStatic = '' //作为发现蓝牙事件的唯一值 用来控制反复订阅多个该事件
let BLECharacteristicValueChange = '' //作为蓝牙特征值变化事件的唯一值 用来控制反复订阅多个该事件

//这里根据公司的设备来的(由硬件服务方提供)，比如需要蓝牙配网的设备必须拥有符合公司给定的服务以及特征 我们才能给该蓝牙设备进行配网或者其他操作。不然其他设备也无法识别我们发送的数据指令
let BleBTStaticConfig = {
	serviceId: '6E400005-B5A3-F393-E0A9-E50E24DCCA9E',
	characteristicId: '6E400003-B5A3-F393-E0A9-E50E24DCCA9E',
	writeId: '6E400002-B5A3-F393-E0A9-E50E24DCCA9E'
}


export default class BleBT {

	reOpenAdapter = true //但检测到蓝牙适配器关闭时，是否开启自动重启蓝牙适配器

	state = {
		BTAdapterState: false, //是否开启了手机蓝牙适配器。若手机蓝牙状态异常是无法开启BT蓝牙适配器
		BTDiscovering: false, //前提只有手机蓝牙适配器处于开启状态，才能进行蓝牙搜索。当前蓝牙是否处于搜索状态
	}

	//开启搜索蓝牙时的配置 比如需要搜索拥有哪些服务的蓝牙设备
	discoverConfig = {
		services: [], //要搜索的蓝牙设备主 service 的 uuid 列表。某些蓝牙设备会广播自己的主 service 的 uuid。如果设置此参数，则只搜索广播包有对应 uuid 的主服务的蓝牙设备。建议主要通过该参数过滤掉周边不需要处理的其他蓝牙设备。
		allowDuplicatesKey: false, //是否允许重复上报同一设备。如果允许重复上报，则 uni.onBlueToothDeviceFound 方法会多次上报同一设备，但是 RSSI 值会有不同。
		powerLevel: 'medium', //扫描模式，越高扫描越快，也越耗电，仅安卓支持。low：低，medium：中，high：高。仅京东小程序支持
		maxTime: 60, //最大搜索时间 秒
	}

	discoverBTdevices = [] //搜索发现的蓝牙设备

	curConnectBTDevice = {
		deviceId: null,
		serviceId: "", //我们生产的蓝牙设备中所定义的配网服务id， 连接的蓝牙硬件设备中必须存在该服务。否则我们无法对该设备进行配网，以及监听该低功耗设备发出的信息
		characteristicId: "", //我们生产的蓝牙设备中所定义的配网服务的特征值， 连接的蓝牙硬件设备中必须存在该服务。否则我们无法对该设备进行配网
	} //当前连接的低功耗蓝牙设备的信息

	constructor() {
		this.initBleBT()
	}

	//全局发送ble蓝牙事件消息
	sendGlobalMsg(msgPayload) {
		uni.$emit('onBleBTMsg', msgPayload)
	}

	//初始化蓝牙
	async initBleBT() {
		await this.openAdapter()

	}

	//打开手机蓝牙适配器
	openAdapter() {
		let _this = this

		return new Promise((resolve, reject) => {
			if (_this.state.BTAdapterState) { //如果蓝牙适配器已经开启则直接返回
				console.log('蓝牙适配器已处于开启状态，无需重新打开')
				reject('蓝牙适配器已处于开启状态，无需重新打开')
				return
			}


			//重置状态
			_this.state.BTAdapterState = false
			_this.state.BTDiscovering = false


			uni.openBluetoothAdapter({
				success() {
					uni.getBluetoothAdapterState({
						success({
							available,
							discovering
						}) {
							_this.state.BTAdapterState = available
							_this.state.BTDiscovering = discovering
							console.log(
								`成功开启蓝牙适配器。已获取蓝牙状态:适配器状态${available},是否处于搜索状态${discovering}`
							)

							//监听手机蓝牙状态
							uni.onBluetoothAdapterStateChange(({
								available,
								discovering
							}) => {
								_this.state.BTAdapterState = available
								_this.state.BTDiscovering = discovering


								if (!_this.state.BTAdapterState && _this
									.reOpenAdapter) {
									console.log('蓝牙适配器已关闭正在尝试重启')
									_this.openAdapter() //重新连接
								}
								_this.sendGlobalMsg({
									EventType: 'BTStateChange', //消息类型用户蓝牙状态发生了变化 例如适配器打开或关闭 |搜索附近蓝牙的状态发生了变化
									BTAdapterState:available,
									BTDiscovering:discovering
								})


							})


							resolve()
						},
						fail(err) {
							console.log('获取蓝牙状态失败',
								err) //状态码返回10001表示 手机没有将蓝牙打开所以无法初始化蓝牙适配器
							reject(err)
						}
					})
				},
				fail(err) {

					uni.showToast({
						title: '开启蓝牙适配器失败,请检查手机蓝牙是否打开',
					})
					reject(err)
				}
			})
		})
	}



	//开始搜索附近蓝牙设备 若已处于搜索状态会停止上一次的搜索并清空搜索信息。重新开启新一轮搜索
	discoverBT() {
		let _this = this
		return new Promise(async (resolve, reject) => {

			//如果蓝牙适配器未开启不能进行蓝牙搜索
			if (!_this.state.BTAdapterState) {
				uni.showToast({
					title: '开启蓝牙搜索失败。蓝牙适配器未开启或已关闭',
				})
				reject('开启蓝牙搜索失败。蓝牙适配器未开启或已关闭')
				return
			}
			//如果正处于搜索状态，则先停止蓝牙搜索
			if (_this.state.BTDiscovering) {
				await uni.stopBluetoothDevicesDiscovery()
				_this.state.BTDiscovering = false
			}
			_this.discoverBTdevices = [] //重置附近搜索到的蓝牙设备

			uni.startBluetoothDevicesDiscovery({
				services: _this.discoverConfig.services,
				allowDuplicatesKey: _this.discoverConfig.allowDuplicatesKey,
				powerLevel: _this.discoverConfig.powerLevel,
				success() {
					_this.state.BTDiscovering = true //将蓝牙搜索状态置为开启状态

					//全局发送开始搜索事件

					_this.sendGlobalMsg({
						EventType: 'BleBTFound', //消息类型 ble蓝牙监听到搜索蓝牙事件
						discoverState: 'start', //搜索状态 'start'|'discovering'|'end' //开始搜索 正在搜索 或是结束搜索
						curFoundDevice: null,
						allFoundDevices: _this.discoverBTdevices //当前已发现的附近的蓝牙设备
					})

					//防止多次调用onBluetoothDeviceFound 监听重复触发回调方法导致数据重复
					if (!BluetoothDeviceFoundStatic) {
						BluetoothDeviceFoundStatic = 'onBluetoothDeviceFound'
						uni.onBluetoothDeviceFound(({
							devices
						}) => {

							_this.discoverBTdevices.push(devices[0])
							_this.sendGlobalMsg({
								EventType: 'BleBTFound', //消息类型 ble蓝牙监听到搜索蓝牙事件
								discoverState: 'discovering', //搜索状态 'start'|'discovering'|'end' //开始搜索 正在搜索 或是结束搜索
								curFoundDevice: devices[0],
								allFoundDevices: _this
									.discoverBTdevices //当前已发现的附近的蓝牙设备
							})
						})
					}

					//开始搜索计时 超过最大搜索时间则停止搜索
					 setTimeout(async () => {
						console.log('搜索已超时准备关闭搜索！')
						await _this.stopDisCoverBT()
					}, _this.discoverConfig.maxTime * 1000)


				},
				fail(err) {
					console.log('开启蓝牙搜索失败,原因:', res)
				}
			})

		})

	}

	//停止搜索附近设备
	stopDisCoverBT() {
		let _this = this
		return new Promise(async (resolve, reject) => {

			//断开蓝牙搜索之前先判断蓝牙是否处于搜索状态
			if (!_this.state.BTDiscovering) {
				console.log('蓝牙未处于搜索状态无法关闭搜索状态')
				reject('蓝牙未处于搜索状态无法关闭搜索状态')
				return
			}
			uni.stopBluetoothDevicesDiscovery({
				success() {
					//全局发送结束搜索事件
					_this.sendGlobalMsg({
						EventType: 'BleBTFound', //消息类型 ble蓝牙监听到搜索蓝牙事件
						discoverState: 'end', //搜索状态 'start'|'discovering'|'end' //开始搜索 正在搜索 或是结束搜索
						curFoundDevice: null,
						allFoundDevices: _this.discoverBTdevices //当前已发现的附近的蓝牙设备
					})
					_this.state.BTDiscovering = false //将蓝牙搜索状态置为关闭状态

					resolve()
				},
				fail(err) {
					uni.showToast({
						title: '关闭搜索失败'
					})
					reject(err)
				}
			})

		})
	}

	//连接低功耗蓝牙设备
	connectBleBT(device) {
		let {
			deviceId
		} = device
		let _this = this
		console.log('进行连接的设备信息', device)
		return new Promise(async (resolve, reject) => {
			//如果已经与其他低功耗蓝牙设备连接 则需要先断开与其他低功耗蓝牙设备的连接
			if (_this.curConnectBTDevice?.deviceId) {
				console.log('检测到已经存在与其他低功耗蓝牙设备连接，准备与该设备断开连接，设备信息:', _this.curConnectBTDevice)
				await _this.disconnectBleDevice()
			}
			
			

			uni.createBLEConnection({
				deviceId,
				success() {
					_this.curConnectBTDevice = device
					console.log('连接设备成功')
					//如果此时蓝牙还处于搜索状态请不要忘记关闭搜索状态
					if (_this.state.BTDiscovering) {
						_this.stopDisCoverBT()
					}
					

					//连接成功后开始监听低功耗蓝牙设备的连接状态
					uni.onBLEConnectionStateChange(({
						deviceId,
						connected
					}) => {
						//如果连接断开 有可能是低功耗蓝牙设备那边连接异常导致的，所以我们这边仍然需要清空我们保存的连接的低功耗蓝牙设备信息
						if (!connected) {
							console.log('蓝牙连接中断')
							_this.curConnectBTDevice = {}
							_this.sendGlobalMsg({
								EventType:'BleDeviceConnectStateChange',//与ble蓝牙设备连接状态发生了变化
								connectedState:connected,
								res:connected?'已连接':'连接中断'
							})
						}
					})

					//设置连接的ble蓝牙设备数据最大传输单元
				 setTimeout(()=>{
						uni.setBLEMTU({
							deviceId,
							mtu: 512,
							success(res) {
								// console.log('最大传输单元设置成功')
								_this.notifyBleBTValueChange()
							},
							fail(err) {
								console.log('最大传输单元设置失败，原因:', err)
							}
						})
					
					},500)


					

					resolve()

				},
				fail(err) {
					console.log('连接设备失败，原因:', err)
					reject(err)
				}
			})

		})
	}


	//对连接的低功耗蓝牙设备进行监听其特征值变化
	notifyBleBTValueChange() {
		let _this = this
		return new Promise((resolve, reject) => {

			//若未连接设备则直接返回
			if (!_this.curConnectBTDevice?.deviceId) {
				console.log('未存在连接的设备，订阅低功耗蓝牙设备特征值失败')
				reject()
				return
			}
			
			
			setTimeout(()=>{
				
				uni.getBLEDeviceServices({
					deviceId: _this.curConnectBTDevice.deviceId,
					success({
						services
					})  {
						//判断该连接的设备是否存在我们公司设备指定的服务项(例如配网服务，音量服务等等，一个蓝牙设备所含有的功能都是一个服务项)，如果连接的设备没有我们公司设备所指定的服务则该设备不为我们公司的设备则不进行发送数据
						let hasCorrectService = services.some(item => item.uuid == BleBTStaticConfig
							.serviceId)
						if (hasCorrectService) {
				
							//只有符合条件的设备才为我们公司的设备 才拥有我们设备所定义的服务id和特征值id
							//订该设备的特征值开启监听，总之就是订阅该设备值变化事件
							uni.notifyBLECharacteristicValueChange({
								state: true,
								deviceId: _this.curConnectBTDevice.deviceId,
								serviceId: BleBTStaticConfig.serviceId,
								characteristicId: BleBTStaticConfig.characteristicId,
								success() {
									console.log('订阅低功耗蓝牙设备特征值变化')
									
									setTimeout(()=>{
							
											console.log('----------------------------------')
											if(!BLECharacteristicValueChange){
												BLECharacteristicValueChange = 'onBLECharacteristicValueChange'
												
												uni.onBLECharacteristicValueChange(function (res) {
												  console.log(`监听到了设备:${_this.curConnectBTDevice.name}的值发生了变化,当前变化值为:${res.value}`)
													_this.sendGlobalMsg({
														EventType:'BleConnectDeviceValueChange',//监听已连接的蓝牙设备值得变化
														value:res.value,
														result:res
													})
												})
											}
											
									
									},500)
									
									
									
									resolve()
								},
								fail(err) {
									console.log('订阅低功耗蓝牙设备特征值失败，原因:', err)
									reject(err)
								}
							})
				
						} else {
							reject()
						}
						
				
				
					},
					fail(err) {
						console.log('获取蓝牙设备服务列表失败,原因:', err)
						reject(err)
					}
				})
				
			},1000)
		})
	}




	//向当前连接的低功耗蓝牙设备发送二进制数据
	sendDataToBleBT(bufferData) {
		let _this = this
		return new Promise((resolve, reject) => {
			if (!_this.curConnectBTDevice?.deviceId) {
				console.log('发送数据失败,当前未连接任何低功耗蓝牙设备')
				reject('当前未连接任何低功耗蓝牙设备')
				return
			}

			uni.getBLEDeviceServices({
				deviceId: _this.curConnectBTDevice.deviceId,
				success({
					services
				}) {
					console.log('deviceId', _this.curConnectBTDevice.deviceId)
					console.log('services', services)
					//判断该连接的设备是否存在我们公司设备指定的服务项(例如配网服务，音量服务等等，一个蓝牙设备所含有的功能都是一个服务项)，如果连接的设备没有我们公司设备所指定的服务则该设备不为我们公司的设备则不进行发送数据
					let hasCorrectService = services.some(item => item.uuid == BleBTStaticConfig
						.serviceId)

					if (hasCorrectService) {

						console.log(_this.curConnectBTDevice.deviceId, BleBTStaticConfig.serviceId,
							BleBTStaticConfig.writeId, bufferData)

						uni.writeBLECharacteristicValue({
							deviceId: _this.curConnectBTDevice.deviceId,
							serviceId: BleBTStaticConfig.serviceId,
							characteristicId: BleBTStaticConfig.writeId,
							value: bufferData,
							success() {
								console.log('发送数据成功,发送数据:', bufferData)
								resolve()
							},
							fail(err) {
								console.log('发送数据失败，原因:', err)
								reject(err)
							}
						})
					} else {
						console.log('发送数据失败，原因: 该设备内部不存在指定服务id，无法对其发送数据')
						reject('该设备内部不存在指定服务id，无法对其发送数据')
					}

				},
				fail(err) {
					console.log('发送数据失败,原因:', err)
					reject(err)
				}
			})


		})

	}



	//断开当前连接的低功耗蓝牙设备
	disconnectBleDevice() {
		let _this = this
		return new Promise((resolve, reject) => {
			if (!_this.curConnectBTDevice?.deviceId) {
				console.log(`未存在已连接的低功耗蓝牙设备。无法断开`)
				reject(`未存在已连接的低功耗蓝牙设备。无法断开`)
				return
			}
			uni.closeBLEConnection({
				deviceId: _this.curConnectBTDevice?.deviceId,
				success() {
					console.log(`与当前低功耗蓝夜设备连接断开，低功耗蓝牙设备信息:`, _this.curConnectBTDevice)
					_this.curConnectBTDevice = {}
					resolve()
				},
				fail(err) {
					console.log('与当前低功耗蓝牙设备无法断开连接，原因:', err)
					reject(err)
				}
			})


		})
	}



	//关闭蓝牙
	closeBT() {
		let _this = this
		return new Promise((resolve, reject) => {
			uni.closeBluetoothAdapter({
				success() {
					_this.state.BTAdapterState = false
					_this.state.BTDiscovering = false
					_this.discoverBTdevices = []
					_this.curConnectBTDevice = {}
				},
				fail(err) {
					reject(err)
				}
			})
		})
	}

}